/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.handlers.commands;

import java.util.HashMap;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.AndroidReceiverException;
import com.hercules.android.receiver.ApplicationData;
import com.hercules.android.receiver.LogUtil;
import com.hercules.android.receiver.ReceiverUtil;
import com.hercules.android.receiver.handlers.commands.CommandHandlersUtil.ValidationException;
import com.hercules.android.receiver.model.commands.XRECommand;
import com.hercules.android.receiver.model.commands.XRERedirectCommand;
import com.hercules.android.receiver.model.objects.XREObject;
import com.hercules.android.receiver.model.objects.XREView;

/**
 * The handler used to process XRERedirectCommand. It will call a configured auxiliary handler for extra handling and
 * the redirect the receiver to new url. It extends XRECommandHandler for convenience.
 * <p>
 * <b>Sample Usage:</b> Please look at sample usage of {@link XREAggregateCommandHandler}.
 * <p>
 * <b>Thread Safety:</b> This class is not thread safe since it has mutable fields. But if they are not changed after
 * first configured, then this class is used in a thread safe manner.
 *
 * @author liuliquan, 7realm
 * @version 1.0
 */
public class XRERedirectCommandHandler extends XRECommandHandler {
    /**
     * The auxiliary handler used to perform extra processing.
     * <p>
     * Initial value is null. Can be any value. If it is null then no extra processing will be performed. It has getter
     * and setter.
     */
    private AuxiliaryXRECommandHandler redirectCommandAuxiliaryHandler;

    /**
     * Default empty constructor.
     */
    public XRERedirectCommandHandler() {
        // empty
    }

    /**
     * Handle given REDIRECT command message.
     *
     * @param command the XRE REDIRECT command to be handled
     * @param receiver the receiver for the XRE application
     * @throws IllegalArgumentException if given command or receiver is null
     * @throws InvalidXRECommandParameterException if url command parameter is null or empty
     * @throws XRECommandHandlerException if any error occurs while handling the command
     */
    @SuppressWarnings("boxing")
    @Override
    protected void processCommandMessage(XRECommand command, AndroidReceiver receiver)
        throws XRECommandHandlerException {
        String methodName = "processCommandMessage";
        LogUtil.enter(getLogger(), this, methodName, command, receiver);

        try {
            // check arguments
            XRERedirectCommand redirectCommand = CommandHandlersUtil.checkCommand(command, XRERedirectCommand.class);
            CommandHandlersUtil.checkNotNull(receiver, "receiver");
            if (receiver.getApplicationConnectData() == null) {
                throw new ValidationException("Value of 'receiver.applicationConnectData' should not be null.");
            }

            // AndroidAssembly1 added parsing of application name
            String url = redirectCommand.getUrl();
            LogUtil.info(getLogger(), this, methodName, "Redirected application {0}, to {1}, reason {2}, status code {3}", 
            	receiver.getApplicationConnectData().getApplicationName(), url, redirectCommand.getReason(), redirectCommand.getStatusCode());

            // process command if auxiliary handler is present
            if (redirectCommandAuxiliaryHandler != null) {
                redirectCommandAuxiliaryHandler.processCommandMessage(redirectCommand, receiver);
            }

            // shut down the receiver
            if (!redirectCommand.isPreserveSession()) {
            	ApplicationData prevApplication = receiver.getApplicationData();
            	//receiver.doShutdown(false);
            	receiver.shutdown(false);
            	receiver.getApplicationData().setParentReceiver(prevApplication.getParentReceiver());
            	receiver.getApplicationData().setParentXREApplicationView(prevApplication.getParentXREApplicationView());
            	
            	HashMap<Integer, XREObject> elementsMap = new HashMap<Integer, XREObject>();
            	XREView rootXREView = (XREView) prevApplication.getElementsXREIdToObject().get(XREObject.ID_ROOT_VIEW);
                elementsMap.put(rootXREView.getId(), rootXREView);

                receiver.getApplicationData().setElementsXREIdToObject(elementsMap);
            } else {
            	//receiver.doShutdown(true);
            	receiver.shutdown(true);
            }

            // set the redirect url and application name
            CommandHandlersUtil.checkStringParameter("url", url);
            if (-1 != url.lastIndexOf('?')) {
	            String urlString = url.substring(0, url.lastIndexOf('?'));
	            String paramsString = url.substring(url.lastIndexOf('?') + 1);
	            
	            receiver.getApplicationConnectData().setUrl(urlString);
	            receiver.getApplicationConnectData().setApplicationName(ReceiverUtil.getAppNameFromUrl(urlString));
	            receiver.getApplicationConnectData().setAppParams(ReceiverUtil.getAppParams(paramsString));
            } else {
            	receiver.getApplicationConnectData().setUrl(url);
	            receiver.getApplicationConnectData().setApplicationName(ReceiverUtil.getAppNameFromUrl(url));
            }
            // connect the receiver
            receiver.connect(false);

            LogUtil.exit(getLogger(), this, methodName);
        } catch (IllegalArgumentException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (XRECommandHandlerException e) {
            throw LogUtil.error(getLogger(), this, methodName, e);
        } catch (ValidationException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XRECommandHandlerException(e.getMessage(), e));
        } catch (AndroidReceiverException e) {
            throw LogUtil.error(getLogger(), this, methodName, new XRECommandHandlerException(
                "Error occurred while reconnecting receiver.", e));
        }
    }

    /**
     * Gets the auxiliary handler used to perform extra processing.
     *
     * @return the auxiliary handler used to perform extra processing
     */
    public AuxiliaryXRECommandHandler getRedirectCommandAuxiliaryHandler() {
        return redirectCommandAuxiliaryHandler;
    }

    /**
     * Sets the auxiliary handler used to perform extra processing.
     *
     * @param redirectCommandAuxiliaryHandler the auxiliary handler used to perform extra processing
     */
    public void setRedirectCommandAuxiliaryHandler(AuxiliaryXRECommandHandler redirectCommandAuxiliaryHandler) {
        this.redirectCommandAuxiliaryHandler = redirectCommandAuxiliaryHandler;
    }
}